package edu.alaska.uaa.cs401.fgm;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * since they're not written in the project anywhere... the following are rules
 * 
 *  if a capturing move is possible, the first move made on a turn must be a capturing move
 *  		subsequent moves need not be captures
 *  the only move allowed to be a simple move is the first move in a turn.
 *  a piece must change direction after moving
 *    ( B W _ _ B )
 *    ( X - W _ B )
 *    ( X - - W B ) <-- this is NOT ALLOWED.
 *  there is no passing on a move.  you may only pass once you've made a required capture.
 */


public class FanoronaBoard implements FanoronaBoardInterface {
	//Board representation

	// [x][y]
	private Cell[][] board = new Cell[9][5];

	/* (non-Javadoc)
	 * @see edu.alaska.uaa.cs401.fgm.FanoronaBoardInterface#getCellColor(int, int)
	 */
	public FanoronaColor getCellColor(int x, int y) {
		int q = board[x][y].getPiece();
		switch (q) {
		case 1:
			return FanoronaColor.White;
		case -1:
			return FanoronaColor.Black;
		default:
			return null;
		}
	}

	public FanoronaBoard()
	{
		/*
	                System.out.println("Just set all the areas in board into cells");
	                //*/

		for(int i = 0;i < 9;i++)
		{
			for(int n = 0;n<5;n++)
			{
				board[i][n] = new Cell();

				//set the pieces up
				if(n <2)
					board[i][n].setPiece(1);
				if(n==2&&(i==1||i==3||i==6||i==8))
					board[i][n].setPiece(1);
				if(n==2&&(i==0||i==2||i==5||i==7))
					board[i][n].setPiece(-1);
				if(n >2)
					board[i][n].setPiece(-1);
			}
		}
		board[4][2].setPiece(0);
		printBoard();

		for(int i = 0;i < 9;i++)
		{
			for(int n = 0;n<5;n++)
			{
				// point to cell above
				if(n < 4)
					board[i][n].addNeighbor(board[i][n+1]);
				else
					board[i][n].addNeighbor(null);
				// to the upper right diagonal
				if((i%2 == 0 && i<8 && (n == 0 || n==2))|| ((n==1 || n==3)&&i%2==1))
					board[i][n].addNeighbor(board[i+1][n+1]);
				else
					board[i][n].addNeighbor(null);
				// point to cell to the right
				if(i < 8)
					board[i][n].addNeighbor(board[i+1][n]);
				else
					board[i][n].addNeighbor(null);
				// to the lower right diagonal
				if((i%2 == 0 && i<8 && (n == 4 || n==2))|| ((n==1 || n==3)&&i%2==1))
					board[i][n].addNeighbor(board[i+1][n-1]);
				else
					board[i][n].addNeighbor(null);
				// point to cell to the bottom
				if(n > 0)
					board[i][n].addNeighbor(board[i][n-1]);
				else
					board[i][n].addNeighbor(null);
				// to the lower left diagonal
				if((i%2 == 0 && i>0 && (n == 4 || n==2))|| ((n==1 || n==3)&&i%2==1))
					board[i][n].addNeighbor(board[i-1][n-1]);
				else
					board[i][n].addNeighbor(null);
				// point to cell to the left
				if(i > 0)
					board[i][n].addNeighbor(board[i-1][n]);
				else
					board[i][n].addNeighbor(null);
				// to the upper left diagonal
				if((i%2 == 0 && i>0 && (n == 0 || n==2))|| ((n==1 || n==3)&&i%2==1))
					board[i][n].addNeighbor(board[i-1][n+1]);
				else
					board[i][n].addNeighbor(null);
			}
		}
		/*
	                for(int i = 0;i<9;i++)
	                        for(int n = 0; n < 5;n++)
	                                testing_the_linking(i,n);

	                System.out.println("Just setup all the neighbors");//*/
	}

//	private void testing_the_linking(int i, int j)
//	{
//		// to be able to run this, change the Cell.neighbors[] from private to public
//		for (int n = 0;n < 9;n++)
//		{
//			try {
//				System.out.println("["+i+"]["+j+"] neighbor "+n+":"+board[i][j].neighbors[n].getPiece());
//			} catch (Exception e) {
//				// TODO Auto-generated catch block
//				System.out.println(e.getMessage());
//			}
//		}
//	}

	private class Cell
	{
		private Cell[] neighbors = new Cell[9];
		private int piece; // -1 = black, 0 = empty, 1 = white
		private int neighbor_counter;
		private int numberOfNeighbors;

		public Cell()
		{
			piece = 0;
			neighbor_counter = 0;
			numberOfNeighbors = 0;
		}

		public boolean isNeighbor(Cell testie, int direction) {
			if(neighbors[direction] == testie)
				return true;
			else
				return false;
		}

		public boolean addNeighbor(Cell neighbor) {
			if(neighbor_counter < 9)
			{
				neighbors[neighbor_counter] = neighbor;
				neighbor_counter++;
				if(neighbor != null)
					numberOfNeighbors++;
				return true;
			}
			else
				return false;
		}

		public int getPiece() {
			return piece;
		}

		public void setPiece(int piece) {
			this.piece = piece;
		}

		public int pieceOpposite() {
			return -piece;
		}
	}
	
	public void setPiece(int x, int y, int piece)
	{
		board[x][y].setPiece(piece);
	}

	/* (non-Javadoc)
	 * @see edu.alaska.uaa.cs401.fgm.FanoronaBoardInterface#stringBoard()
	 */
	public String stringBoard() {
		StringBuilder ret = new StringBuilder();
		for(int n = 4; n>=0;n--)
		{
			for(int i = 0; i < 9;i++)
			{
				if(board[i][n].getPiece() >0)
				{
					ret.append('W');
				}
				else if(board[i][n].getPiece()<0)
				{
					ret.append('B');
				}
				else
				{
					ret.append(' ');
				}
			}
			ret.append('\n');
		}
		return ret.toString();
	}

	public void printBoard()
	{
		System.out.println(stringBoard());
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		FanoronaBoard game_board = new FanoronaBoard();
		game_board.printBoard();
	}

	public boolean validateMove(String[] input, FanoronaColor color) {
		// Added a color argument since it's not possible to verify that a move is
		// valid without knowing who is making the move.
		
		int xStart, yStart, yEnd, xEnd;
		String move_type;
		int direction,dirX,dirY;
		int[] node = new int[2];
		ArrayList<int[]> previous_positions = new ArrayList<int[]>();
		// need to make sure that the first move in the sequence is a
		//  normal move ONLY if there is no capture moves possible
		for(int i = 0;i<(input.length/5);i++)
		{
			move_type = input[i*5+0];
			xStart = node[0] = Integer.parseInt(input[i*5+1]);
			yStart = node[1] = Integer.parseInt(input[i*5+2]);
			xEnd = Integer.parseInt(input[i*5+3]);
			yEnd = Integer.parseInt(input[i*5+4]);
			dirX = xEnd-xStart;
			dirY = yEnd-yStart;
			System.out.println(i+" "+move_type+xStart+yStart+xEnd+yEnd+": "+dirX+","+dirY);
			
			System.out.println(node[0]+","+node[1]);
			// puts the start position on the list of previous positions in this move sequence
			previous_positions.add(node);
			// if the end position has already been inhabited this move sequence, the move sequence fails
			for(int n = 0;n<previous_positions.size();n++)
			{
				node = previous_positions.get(n);
				if(node[0] == xEnd && node[1] == yEnd)
				{
					System.out.println("This position already visited");
					return false;
				}
			}

			if(dirX  == 0 && dirY == 1)
				direction = 0;
			else if(dirX  == 1 && dirY == 1)
				direction = 1;
			else if(dirX  == 1 && dirY == 0)
				direction = 2;
			else if(dirX  == 1 && dirY == -1)
				direction = 3;
			else if(dirX  == 0 && dirY == -1)
				direction = 4;
			else if(dirX  == -1 && dirY == -1)
				direction = 5;
			else if(dirX  == -1 && dirY == 0)
				direction = 6;
			else if(dirX  == -1 && dirY == 1)
				direction = 7;
			else direction = -1;
			
			System.out.println(direction);
			// Test to see if the space they are trying to move to is a neighbor of where they are moving from
			if(!board[xStart][yStart].isNeighbor(board[xEnd][yEnd], direction))
				return false;
			else
				System.out.println("The two spaces are neighbors.");
			
			if(board[xEnd][yEnd].getPiece() != 0)
				return false;
			else
				System.out.println("Move into an empty space.");
			
			if(move_type.equalsIgnoreCase("w"))
			{
				//need to reverse the direction to look behind us
				dirX = 0-dirX;
				dirY = 0-dirY;
				if(direction == 0)
					direction = 4;
				else if(direction == 1)
					direction = 5;
				else if(direction == 2)
					direction = 6;
				else if(direction == 3)
					direction = 7;
				else if(direction == 4)
					direction = 0;
				else if(direction == 5)
					direction = 1;
				else if(direction == 6)
					direction = 2;
				else if(direction == 7)
					direction = 3;
				else direction = -1;
				System.out.println("checking behind in direction: "+direction+" position:"+(xStart+dirX)+","+(yStart+dirY));
				// if there is a neighbor cell 'behind' the moving piece
				if(board[xStart][yStart].isNeighbor(board[xStart+dirX][yStart+dirY], direction))
				{
					System.out.println("They are neighbors.");
					// if the piece there is an enemy piece
					if(board[xStart+dirX][yStart+dirY].getPiece() == board[xStart][yStart].pieceOpposite())
					{
						System.out.println("The piece withdrawing from is an enimy piece.");
						// it is a valid withdraw capture.
					}
					else
						return false;
				}
				else
					return false;
			}
			else if(move_type.equalsIgnoreCase("c"))
			{
				// if the space they are moving their piece to is an empty spot
				if(board[xEnd][yEnd].getPiece() == 0)
					// if the piece two spaces ahead is an enemy piece
					if(board[xStart][yStart].getPiece() == -board[xEnd+dirX][yEnd+dirY].getPiece())
						// it is a valid advance capture.
						return true;
			}
			// need to run the Cell's boolean
			//		isNeighbor(Cell testie, int direction)
			// to test to see if hte move is a valid neighbor
			// need to make a list of places already been, to make sure
			// they are not trying to move onto a spot they already have
			// been on
			// need to make sure they are not trying to withdraw capture
			// and capture capture with the same move, even if disguised
		}
		return true;
		// Just noted something.  the pieces are allowed to move only into blank spaces,
		// but unless pieces are captured as part of the validations process, they will almost always return false,
		// since some of the spaces that they are trying to move into are not empty, even though they would be empty
		// through process of capture.
		
		// Basicaly, need to have a capture function done before can do too much more on the validation.
		// the best way to do this is to make an internal copy of the board, capture pieces off of and validate
		// that, then throw it away when the validation is done.
		
		// ---
		// or we can skip "validation" and simply update the board after saving a copy and, if it
		// fails, revert and throw a FanoronaMoveException.
		
	}

	/* (non-Javadoc)
	 * @see edu.alaska.uaa.cs401.fgm.FanoronaBoardInterface#getWinner()
	 */
	public FanoronaColor getWinner() {
		// TODO Auto-generated method stub
		return null;
	}

	public String[] validateMoveFormat(String input) {
		String[] output = input.split(" ");
		Pattern move_type = Pattern.compile("[wcmWCM]");
		Pattern position = Pattern.compile("[0-8]");
		for(int i = 0; i < output.length;i++)
		{
			Matcher correct_move = move_type.matcher(output[i]);
			Matcher correct_position = position.matcher(output[i]);
			
			if(!correct_move.find(0)&&!correct_position.find(0))
			{
				// This input is just wrong.
				System.out.println(output[i]+" fails because just wrong");
				output[0] = "Epic Fail";
				return output;
			}
			else if(i%5 == 0 && !correct_move.find(0))
			{
				System.out.println(output[i]+" "+i%5+" "+correct_move+" fails because inforrect move type");
				output[0] = "Epic Fail";
				return output;
			}
			else if((i%5 == 2 ||i%5 == 4)&&Integer.parseInt(output[i])>4)
			{
				System.out.println(output[i]+" fails because this move should be between 0 and 4");
				output[0] = "Epic Fail";
				return output;
			}
			else if((i%5 == 1 ||i%5 == 3)&&!correct_position.find(0))
			{
				System.out.println(output[i]+" fails because this move should be between 0 and 8");
				output[0] = "Epic Fail";
				return output;
			}
		}
		return output;
	}

	/* (non-Javadoc)
	 * @see edu.alaska.uaa.cs401.fgm.FanoronaBoardInterface#processMove(java.lang.String, edu.alaska.uaa.cs401.fgm.FanoronaColor)
	 */
	public void processMove(String l, FanoronaColor currentMover) throws FanoronaMoveException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String getLog() {
		// TODO Auto-generated method stub
		return null;
	}
}
